# frozen_string_literal: true

module QA
  RSpec.describe 'Govern', :runner, :reliable, :external_api_calls, product_group: :threat_insights do
    describe 'Project vulnerability report' do
      let(:vuln_name) { "Regular Expression Denial of Service in debug" }
      let(:vuln_description) do
        "The debug module is vulnerable to regular expression denial of service when untrusted
         user input is passed into the `o` formatter. It takes around 50k characters to block
         for 2 seconds making this a low severity issue."
      end

      let(:report_with_finding) { "gl-dependency-scanning-report-1.json" }
      let(:report_with_finding_removed) { "gl-dependency-scanning-report-2.json" }
      let!(:project) do
        Resource::Project.fabricate_via_api! do |project|
          project.name = 'project-with-secure'
          project.description = 'To test fix vulnerability workflow'
          project.group = create(:group)
        end
      end

      let!(:runner) do
        create(:project_runner, project: project, name: "runner-for-#{project.name}", tags: ['secure_report'])
      end

      let!(:repository) do
        Resource::Repository::ProjectPush.fabricate! do |project_push|
          project_push.project = project
          project_push.directory = Pathname.new(
            EE::Runtime::Path.fixture('fix_vulnerability_workflow_premade_reports')
          )
        end
      end

      before do
        Flow::Login.sign_in
        project.visit!
      end

      after do
        runner.remove_via_api!
      end

      it 'validates "fix a vulnerability" workflow',
        testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/362599' do
        run_new_pipeline(report: report_with_finding, pipeline_count: 1)

        EE::Page::Project::Secure::SecurityDashboard.perform do |security_dashboard|
          security_dashboard.wait_for_vuln_report_to_load

          expect(security_dashboard).to have_vulnerability(description: vuln_name)
        end

        run_new_pipeline(report: report_with_finding_removed, pipeline_count: 2, update: true)

        EE::Page::Project::Secure::SecurityDashboard.perform do |security_dashboard|
          Support::Retrier.retry_on_exception(
            max_attempts: 3,
            reload_page: page,
            message: "retrying for remediation badge"
          ) do
            expect(security_dashboard).to have_remediated_badge(vuln_name)
          end
        end

        EE::Page::Project::Secure::SecurityDashboard.perform do |security_dashboard|
          security_dashboard.select_single_vulnerability(vuln_name)
          security_dashboard.change_state('resolved')
        end

        EE::Page::Project::Secure::Show.perform do |security_dashboard|
          security_dashboard.filter_by_status(['resolved'])

          expect(security_dashboard).to have_status('resolved', vuln_name)
        end

        run_new_pipeline(report: report_with_finding, pipeline_count: 3, update: true)

        EE::Page::Project::Secure::Show.perform do |security_dashboard|
          security_dashboard.filter_by_status(['all statuses'])

          expect(security_dashboard).to have_status('needs triage', vuln_name)
        end

        EE::Page::Project::Secure::SecurityDashboard.perform do |security_dashboard|
          expect(security_dashboard).not_to have_remediated_badge(vuln_name)
        end
      end

      private

      def run_new_pipeline(report:, pipeline_count:, update: false)
        create_commit(report, update)

        expect { project.pipelines.size }.to eventually_eq(pipeline_count).within(max_duration: 60),
          "There are currently #{project.pipelines.size} pipelines in the project instead of #{pipeline_count}"

        Flow::Pipeline.wait_for_latest_pipeline(status: 'passed')
        Page::Project::Menu.perform(&:go_to_vulnerability_report)
      end

      def ci_file(report_name)
        {
          file_path: '.gitlab-ci.yml',
          content: <<~YAML
            include:
              template: Dependency-Scanning.gitlab-ci.yml
              template: Container-Scanning.gitlab-ci.yml
              template: SAST.gitlab-ci.yml

            dependency_scanning:
              tags: [secure_report]
              script:
                - echo "Skipped"
              artifacts:
                reports:
                  dependency_scanning: #{report_name}
          YAML
        }
      end

      def create_commit(report_name, update)
        Resource::Repository::Commit.fabricate_via_api! do |commit|
          commit.project = project
          if update
            commit.commit_message = 'Update .gitlab-ci.yml'
            commit.update_files([ci_file(report_name)])
          else
            commit.commit_message = 'Add .gitlab-ci.yml'
            commit.add_files([ci_file(report_name)])
          end
        end
      end
    end
  end
end
